package cn.jtfadmin.base.lang.config.statuscode;


import cn.jtfadmin.base.lang.common.utils.RequestUtils;
import cn.jtfadmin.base.lang.config.ApplicationHolder;
import cn.jtfadmin.base.lang.config.WebConfig;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 公共-状态码管理器
 *
 * @author jtf
 * @see StatusCodeConfig
 * @see StatusCodeManager
 * @see WebConfig#configureHandlerExceptionResolvers(List)
 * @since 0.0.1
 */
@Component
public class StatusCodeManager implements InitializingBean {


    @Autowired(required = false)
    private List<StatusCodeConfig> list = new ArrayList<>();

    /**
     * 状态码配置
     */
    private Map<Integer, StatusDescribe> statusDescribeMap;

    private Map<Class<? extends Throwable>, ExceptionStatusDescribe> exClassStatusDescribeMap;

    @Override
    public void afterPropertiesSet() throws Exception {
        statusDescribeMap = new TreeMap<>();
        exClassStatusDescribeMap = new HashMap<>();
        list.forEach(t -> {
            t.getStatusDecribes().forEach(statusDescribe -> {
                if (statusDescribeMap.put(statusDescribe.getStatusCode(), statusDescribe) != null) {
                    throw new BeanInitializationException("配置返回状态码重复:" + statusDescribe.getDescribe() + "," + statusDescribe.getStatusCode());
                }
                if (statusDescribe instanceof ExceptionStatusDescribe) {
                    ExceptionStatusDescribe exceptionStatusDescribe = (ExceptionStatusDescribe) statusDescribe;
                    Class<? extends Throwable>[] exClasses = exceptionStatusDescribe.getExClass();
                    for (Class<? extends Throwable> exClass : exClasses) {
                        if (exClassStatusDescribeMap.put(exClass, exceptionStatusDescribe) != null) {
                            throw new BeanInitializationException("配置返回状态吗异常重复:" + exClass + "," + statusDescribe.getStatusCode());
                        }
                    }

                }
            });
        });
        statusDescribeMap = Collections.unmodifiableMap(statusDescribeMap);
        exClassStatusDescribeMap = Collections.unmodifiableMap(exClassStatusDescribeMap);
    }


    /**
     * 获取所有的状体码配置
     *
     * @return 获取所有的状体码配置
     */
    public List<StatusDescribe> getAllNativeStatusDescribe() {
        List<StatusDescribe> list = new ArrayList<>();
        statusDescribeMap.forEach((k, v) -> {
            list.add(v);
        });
        return list;
    }


    /**
     * 按照状态码获取资源消息,
     *
     * @param code   状态码
     * @param locale 语言
     * @return
     */
    public String getMessage(String code, Locale locale) {
        return ApplicationHolder.getApplicationContext().getMessage(code, null, "", locale);
    }


    /**
     * 按照当前线程请求的语言获取
     *
     * @param code
     * @return
     */
    public String getMessageByThreadRequestLocal(Integer code) {
        HttpServletRequest request = RequestUtils.getRequest();
        if (Objects.nonNull(request)) {
            Locale locale = RequestContextUtils.getLocale(request);
            return getMessage(String.valueOf(code), locale);
        } else {
            return null;
        }
    }

    public ExceptionStatusDescribe getExStatusDescribe(Throwable ex) {
        ExceptionStatusDescribe statusDescribe = getExCauseStatusDescribe(ex);
        if (Objects.nonNull(statusDescribe)) {
            return statusDescribe;
        }
        Class<? extends Throwable> clazz = ex.getClass();
        while (clazz != Throwable.class) {
            statusDescribe = exClassStatusDescribeMap.get(clazz);

            if (statusDescribe == null) {
                clazz = (Class<? extends Throwable>) clazz.getSuperclass();
                continue;
            }
            return statusDescribe;
        }

        return DefaultErrorStatusCodeConfig.DEFAULT_ERROR_STATUS_DESCRIBE;

    }

    public ExceptionStatusDescribe getExCauseStatusDescribe(Throwable ex) {
        ExceptionStatusDescribe statusDescribe = null;
        Throwable cause = ex.getCause();
        if (Objects.nonNull(cause)) {
            statusDescribe = getExCauseStatusDescribe(cause);
        }
        if (Objects.isNull(statusDescribe)) {
            statusDescribe = exClassStatusDescribeMap.get(ex.getClass());
        }
        if (Objects.isNull(statusDescribe)) {
            Class<?> superclass = ex.getClass().getSuperclass();
            while (superclass != Object.class && statusDescribe == null) {
                statusDescribe = exClassStatusDescribeMap.get(superclass);
                superclass = superclass.getSuperclass();
            }
        }
        return statusDescribe;


    }


}
